﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using System.Reflection;
using Boardgame;
using BoardgameModel;
using AppInfo;
using WpfGameControls;


namespace WpfChess
{
    public partial class ChessController : Window
    {
        private ChessModel model;

        public ChessController ()
        {
            InitializeComponent();
        }

        #region Checkerboard pseudo-control

        private Cell? selection;
        private Brush lightBrush = Brushes.Tan;
        private Brush darkBrush = Brushes.Brown;
        private Brush hiliteBrush = Brushes.Purple;

        //// Public instance properties:

        public double FontFactor
        {
            get { return 0.9; }
        }

        public Cell? Selection
        {
            get { return selection; }
            set
            {
                if (value == null || value != null && ! value.HasValue)
                {
                    if (selection != null)
                        ChangeHilite (selection.Value.X, selection.Value.Y, false);
                }
                else
                {
                    if (selection.HasValue)
                        if (selection.Value.X == value.Value.X && selection.Value.Y == value.Value.Y)
                            return;
                        else
                            ChangeHilite (selection.Value.X, selection.Value.Y, false);

                    ChangeHilite (value.Value.X, value.Value.Y, true);
                }

                selection = value;
            }
        }

        //// Public instance methods:

        public void ChangeHilite (int cellX, int cellY, bool isHilite)
        {
            TextBlock client = (TextBlock) boardGrid.Children[GridLocFromCell (cellX, cellY)];
            client.Background = isHilite? hiliteBrush : BrushFromCoordinate (cellX, cellY);
        }

        public void ClearHilites ()
        {
            Selection = null;

            for (int y = 0; y < model.Board.SizeY; ++y)
                for (int x = 0; x < model.Board.SizeX; ++x)
                {
                    TextBlock client = (TextBlock) boardGrid.Children[GridLocFromCell (x, y)];
                    client.Background = BrushFromCoordinate (x, y);
                }
        }


        public void ClearContent (int cellX, int cellY)
        {
            TextBlock client = (TextBlock) boardGrid.Children[GridLocFromCell (cellX, cellY)];
            client.Text = null;
        }

        public FontFamily UnicodeSymbolFont
        {
            get { return null; }
        }

        // Display Unicode character.
        public void SetContent (int cellX, int cellY, string text)
        {
            TextBlock client = (TextBlock) boardGrid.Children[GridLocFromCell (cellX, cellY)];
            client.FontSize = boardGrid.ActualHeight / model.Board.SizeY * FontFactor;
            client.TextAlignment = TextAlignment.Center;
            client.VerticalAlignment = VerticalAlignment.Center;
            client.Text = text;
        }


        private void ConstructCheckerboard ()
        {
            for (var cellY = model.Board.SizeY - 1; cellY >= 0; --cellY)
                for (var cellX = 0; cellX < model.Board.SizeX; ++cellX)
                {
                    var client = new TextBlock();
                    client.Tag = boardGrid.Children.Count;
                    boardGrid.Children.Add (client);

                    client.MouseDown += square_MouseDown;
                    client.MouseRightButtonDown += square_MouseRightButtonDown;
                    client.MouseRightButtonUp += square_MouseRightButtonUp;
                    client.Background = BrushFromCoordinate (cellX, cellY);
                }
        }

        //// //// //// //// //// //// //// //// 

        //// Checkerboard user event handlers:

        private void boardGrid_SizeChanged (object sender, SizeChangedEventArgs scArgs)
        {
            if (model != null)
            {
                var newFontSize = boardGrid.ActualHeight / model.Board.SizeY * FontFactor;
                for (var cellY = model.Board.SizeY - 1; cellY >= 0; --cellY)
                    for (var cellX = 0; cellX < model.Board.SizeX; ++cellX)
                    {
                        var client = (TextBlock) boardGrid.Children[GridLocFromCell (cellX, cellY)];
                        client.FontSize = newFontSize;
                    }
            }
        }


        private void square_MouseDown (object sender, MouseButtonEventArgs mArgs)
        {
            if (! model.IsUnderway)
                return;

            var cell = CellFromTag ((int) ((FrameworkElement) sender).Tag);

            if (mArgs.ChangedButton == MouseButton.Left)
            {
                if (Selection.HasValue)
                {
                    if (cell.X == Selection.Value.X && cell.Y == Selection.Value.Y)
                        Selection = null;
                    else
                    {
                        try
                        {
                            model.MakeMove (Selection.Value.X, Selection.Value.Y, cell.X, cell.Y);
                        }
                        catch (Exception ex)
                        {
                            WpfMessageBox.Show (ex.Message, "SORRY");
                        }
                    }
                }
                else if (model.IsMovable (cell.X, cell.Y))
                    Selection = cell;
            }
        }


        private void square_MouseRightButtonDown (object sender, MouseButtonEventArgs mArgs)
        {
            if (! model.IsUnderway)
                return;

            var cell = CellFromTag ((int) ((FrameworkElement) sender).Tag);
            model.BeginShowMoves (cell.X, cell.Y);
        }


        private void square_MouseRightButtonUp (object sender, MouseButtonEventArgs mArgs)
        {
            model.EndShowMoves();
        }

        //// Private helper methods

        private Brush BrushFromCoordinate (int x, int y)
        {
            return (x + y) % 2 != 0 ? lightBrush : darkBrush;
        }

        private int GridLocFromCell (int x, int y)
        {
            return (model.Board.SizeY - 1 - y) * model.Board.SizeY + x;
        }

        private Cell CellFromTag (int gridLoc)
        {
            int newY = gridLoc / model.Board.SizeY;
            int newX = gridLoc - newY * model.Board.SizeY;
            return new Cell (newX, model.Board.SizeY - 1 - newY);
        }

        #endregion

        //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// ////

        #region Controller event handlers

        private void Window_Loaded (object sender, RoutedEventArgs e)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            Title = AppAbout.Title (assembly) + " " + AppAbout.Version (assembly);

            // Create the model.
            model = new ChessModel();

            // Create widgets that are dependent on the Model.
            ConstructCheckerboard();

            // Create the view and connect it to the controller and model.
            var view = new ChessView (this, model);
        }


        private void promoList_SelectionChanged (object sender, SelectionChangedEventArgs sArgs)
        {
            if (sArgs.AddedItems.Count == 1)
            {
                ListBoxItem item = sArgs.AddedItems[0] as ListBoxItem;
                if (model.CurrentPlayerPromotionName.CompareTo (item.Content.ToString()) != 0)
                    model.SetPromotion (item.Content.ToString());
            }
        }

        #endregion

        #region Controller menu event handlers

        private void fileMenuExit_Click (object sender, RoutedEventArgs e)
        {
            Close();
        }

        //// //// //// //// //// //// //// ////

        private void gameMenuUndo_Click (object sender, RoutedEventArgs e)
        {
            model.UndoMove();
        }

        private void gameMenuNew_Click (object sender, RoutedEventArgs e)
        {
            model.Setup();
        }

        private void gameMenuResign_Click (object sender, RoutedEventArgs e)
        {
            model.ResignGame();
        }

        ////

        private void drawMenuRequest_Click (object sender, RoutedEventArgs e)
        {
            model.RequestDraw();
        }

        private void drawMenuFiftyMoves_Click (object sender, RoutedEventArgs e)
        {
            model.RequestFiftyMovesRuleDraw();
        }

        private void drawMenuThreefoldNow_Click (object sender, RoutedEventArgs e)
        {
            model.RequestThreefoldRepetitionDrawNow();
        }

        private void drawMenuRepetitionLater_Click (object sender, RoutedEventArgs e)
        {
            model.IsThreefoldRepDrawOnMoveRequested = ! model.IsThreefoldRepDrawOnMoveRequested;
        }

        //// //// //// //// //// //// //// //// 

        private void helpMenuAbout_Click (object sender, RoutedEventArgs e)
        {
            Window dialog = new WpfAbout();
            dialog.Owner = this;
            bool? result = dialog.ShowDialog();
        }

        #endregion
    }
}
